<template>
  <div class="upload-container upload-custom-container">
    <div>
      <draggable v-if="isImg" v-model="fileList" @end="dragEnd">
        <div v-for="(item, i) in fileList" :key="i" class="card animated fadeInDown">
          <div v-if="item.url" class="img-wrapper">
            <img :src="item.url" />
          </div>
          <div class="ctrl-wrapper">
            <i @click="preview(item)" class="el-icon-view"></i>
            <i @click="remove(item, i)" class="el-icon-delete"></i>
          </div>
        </div>
      </draggable>
      <div @click="showUpload" v-if="fileList.length < limit" class="card" :class="isImg ? 'add-card' : 'add-not-card'">
        <i class="el-icon-plus"></i>
        <input :multiple="limit > 1" @change="upload" :accept="accept" type="file" v-show="false" ref="input">
      </div>
      <div v-if="!isImg" v-for="(item, i) in fileList" :key="i" class="uploaded-item">
        {{item.url}} <i @click="remove(item, i)" class="el-icon-error"></i>
      </div>
    </div>
    <p v-if="tip" class="tip">{{tip}}</p>
    <el-dialog append-to-body :visible.sync="visible">
      <img v-if="activeItem.url" width="100%" :src="activeItem.url" alt="">
    </el-dialog>
  </div>
</template>

<script>
  import axios from 'axios'
  import draggable from 'vuedraggable'
  import {Indicator} from 'kuan-bear-vue'

  import { aliToken } from '@/api/uploadToken'
  import SparkMD5 from 'spark-md5'

  export default {
    props: {
      value: {
        type: Array,
        default() {
          return []
        }
      },
      tip: {
        type: String,
        default: ''
      },
      limit: {
        type: Number,
        default: 1
      },
      size: {
        type: Number,
        default: 60000
      },
      accept: {
        type: String,
        default: 'image/png, image/jpeg, image/gif'
      },
      module: {
        type: String,
        // default: 'store'
        default: ''
      },
      validate: {
        type: Function
      },
    },
    computed: {
      isImg() {
        return this.accept === 'image/png, image/jpeg, image/gif'
      }
    },
    data() {
      return {
        visible: false,
        fileList: this.value,
        formData: {
          'x:module': this.module
        },
        action: 'https://dashboard-static.oss-cn-hangzhou.aliyuncs.com',
        activeItem: {}
      }
    },
    watch: {
      value(e) {
        this.fileList = e
      }
    },
    methods: {
      getName(file) {
        return new Promise(resolve => {
          const {name} = file
          const suffix = name.substr(name.lastIndexOf('.'))
          const spark = new SparkMD5.ArrayBuffer()
          const reader = new FileReader()
          reader.readAsArrayBuffer(file)
          reader.addEventListener('load', (e) => {
            spark.append(e.target.result)
            resolve(spark.end() + suffix) // 文件md5加密，放置重复上传
          })
        })
      },
      async beforeUpload(file) {
        if (file.size / 1000 > this.size) {
          const message = '图片过大'
          this.$message.warning(message)
          return Promise.reject(message)
        }
        if (this.validate) {
          await this.validate(file)
        }
        const name = await this.getName(file)
        const {accessid, callback, dir, policy, signature, host} = await aliToken()
        this.formData['key'] = `${dir}${name}`
        this.action = host
        this.formData['OSSAccessKeyId'] = accessid
        this.formData['policy'] = policy
        this.formData['Signature'] = signature
        this.formData['callback'] = callback
        return true
      },
      async showUpload() {
        const {input} = this.$refs
        input.click()
      },
      async uploadItem(file) {
        await this.beforeUpload(file)
        Indicator.open()
        const fd = new FormData()

        Object.entries(this.formData).forEach(([key, value]) => {
          fd.append(key, value)
        })
        fd.append('file', file)
        const {data} = await axios({
          url: this.action,
          method: 'post',
          data: fd
        })
        // const {domain, file_id, file_path} = data
        const {base_url, path, id, width, height} = data
        const item = {
          url: this.isImg ? `${base_url}${path}-300x300` : `${base_url}${path}`,
          id: id,
          width: width,
          height: height,
          path: path
        }
        this.fileList.push(item)
        this.$emit('success', item)
        this.change()
        Indicator.close()
      },
      upload() {
        const {files = []} = this.$refs.input
        try {
          for (let i = 0; i < files.length; i++) {
            this.uploadItem(files[i])
          }
        } catch (e) {
          this.$message.warning(e.message)
        }
      },
      change() {
        const value = this.fileList
        this.$emit('change', value)
        this.$emit('input', value)
      },
      preview(item) {
        this.activeItem = item
        this.visible = true
      },
      remove(item, i) {
        this.fileList = this.fileList.filter((it, index) => index !== i)
        this.change()
        this.$emit('remove', item)
      },
      dragEnd() {
        this.change()
        this.$emit('sort', this.fileList)
      }
    },
    components: {
      draggable
    }
  }
</script>

<style lang="scss" scoped>
.upload-container {
  display: inline-block;
}

.card {
  overflow: hidden;
  border-radius: 6px;
  box-sizing: border-box;
  width: 120px;
  height: 120px;
  margin: 0 8px 8px 0;
  display: inline-block;
  border: 1px solid #c0ccda;
  line-height: 120px;
  vertical-align: top;
  text-align: center;
  position: relative;
  &:hover {
    .ctrl-wrapper {
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      display: block;
    }
  }
  &.add-card {
    border: 1px dashed #c0ccda;
    background-color: #fbfdff;
    font-size: 28px;
    color: #8c939d;
    &:hover {
      border-color: #409eff;
      color: #409eff;
    }
  }
  &.add-not-card {
    border: 1px dashed #c0ccda;
    background-color: #fbfdff;
    font-size: 20px;
    color: #8c939d;
    width: 50px;
    height: 50px;
    .el-icon-plus {
      display: flex;
      justify-content: center;
      margin-top: 14px;
    }
  }
  .img-wrapper {
    width: 100%;
    height: 100%;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    img {
      width: 100%;
    }
  }
}

.ctrl-wrapper {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  color: white;
  font-size: 20px;
  display: none;
  i {
    padding: 0 8px;
  }
}
.uploaded-item {
  line-height: 2;
  i {
    padding: 0 10px;
  }
}
.tip {
  color: gray;
  padding: 0;
  margin: 0;
}
</style>

<style>
.upload-custom-container > div {
  display: inline-block;
}
</style>
